package pervasivePositioning.pos;
	
import java.io.IOException;

import pervasivePositioning.androidPositioner.PositionService;
import pervasivePositioning.androidPositioner.Report;
import pervasivePositioning.androidPositioner.TCPPositionService;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import pervasivePositioning.pos.Coordinate;

public class Positioner {
//	PositioningService ui;
	static AccelerometerService accelerometerService;
	
    SensorManager sm;
	LocationManager lm;
	LocationListener locationListener;
	Activity activity;
	static float[] acceleration = null;
	static boolean inMotion = true; 
	
	static ReportingStrategy[] strategies;
	boolean[] strategiesEnabled;
	PositionService[] consumers;

	public Positioner(PositionService consumer, AccelerometerService accConsumer, Activity a) throws IOException {
		activity = a;
		accelerometerService = accConsumer;
		
		consumers = new PositionService[] {
			consumer,
//			new TCPPositionService("86.52.40.222", 5432),
			new TCPPositionService("84.238.42.244", 5432),
			new PosHistory()
		};

		strategies = new ReportingStrategy[]{
			new PeriodicStrategy(),
			new DistanceStrategy(),
			new MaxSpeedStrategy(),
			new AccelerationStrategy()
		};
		
		strategiesEnabled = new boolean[] {
			true,
			false,
			false,
			false
		};
		
		lm = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
        locationListener = new locListener();
	      
        sm = (SensorManager)activity.getSystemService(Context.SENSOR_SERVICE);
        enableFilter(0, true);
        
        ((PosHistory) consumers[2]).setSendReceiver(consumers[1]);
        ((TCPPositionService) consumers[1]).enable(true);
  	}

	
	public void enableFilter(int index, boolean enabled) {
		strategiesEnabled[index] = enabled;
		enableListeners();
	}
	
	public boolean isStrategyEnabled(int index) {
		return strategiesEnabled[index];
	} 
	
	public void setProperties(float time, float distance, float speed, float threshold)
	{
		((PeriodicStrategy) strategies[0]).setValue(time);
		((DistanceStrategy) strategies[1]).setValue(distance);
		((MaxSpeedStrategy) strategies[2]).setValue(speed);
		((AccelerationStrategy) strategies[3]).setValue(threshold);
	}
	
	public float getProperty(int index) {
		return strategies[index].getValue();
	}
	
	public void setProperty(int index, float value) {
		strategies[index].setValue(value);
	}
	
		
	public void disableListeners()
	{
		lm.removeUpdates(locationListener);
   		sm.unregisterListener(sensorEventListener);
	}
	
	public void enableListeners()
	{
       	lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
       	
       	if(strategiesEnabled[3])
       		sm.registerListener(sensorEventListener, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
       	else
       		sm.unregisterListener(sensorEventListener);       		
	}

	private String getConfiguration() {
		String config = "";
		for (int i = 0; i < strategies.length; i++) {
			if (strategiesEnabled[i]) {
				config += String.format("%s=%f, ", strategies[i].getValueName(), strategies[i].getValue());
			}
		}

		if (config.endsWith(", ")) {
 			config = config.substring(0, config.length()-3);
		}
		
		return config;
	}
	
	public void send() throws IOException {
    	for (PositionService p : consumers) {
    		p.send();
    	}
	}

	public void save() throws IOException {
    	for (PositionService p : consumers) {
    		p.save();
    	}
	}
	
	public void reset() {
    	for (PositionService p : consumers) {
    		p.reset();
    	}
	}


    private class locListener implements LocationListener {
    	    	
//		@Override
    	public void onLocationChanged(Location location) {
			if (location != null) {
				boolean keepIt = true;
				
				for(int i = 0; i < strategies.length; i++) {
					if (strategiesEnabled[i])
					{
						keepIt = keepIt && strategies[i].reportPosition(location); 
					}
				}
				if (keepIt) {
					Report r = new Report(new Coordinate(location.getLatitude(), location.getLongitude(), location.getAltitude()), location.getTime(), "strategy", "config");
					String config = getConfiguration();

					try {
						for ( PositionService c : consumers) {							
							c.ReportPosition(location.getTime(), new Coordinate(location), new Coordinate(acceleration), config);
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						Log.println(Log.ERROR, "onLocationChanged", e.getLocalizedMessage());
					}
				}
			}	
		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) { }

		@Override
		public void onProviderDisabled(String provider) { }

		@Override
		public void onProviderEnabled(String provider) { }
    }
    

    private static SensorEventListener sensorEventListener = 
        new SensorEventListener() {
 
        public void onSensorChanged(SensorEvent e) {
        	// We update the gui regardless if we are in motion
        	if (e != null && e.values != null) {
            	inMotion = strategies[3].reportAcceleration(e.values);
            	acceleration = e.values;
            	accelerometerService.reportAccelerometer(e.values, inMotion);
            }
        }

		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy) { }
    };     
}
